SUBDIRS += rombios rombios/32bit
SUBDIRS += vgabios
SUBDIRS += vmxassist
+SUBDIRS += extboot
SUBDIRS += hvmloader
.PHONY: all
--- /dev/null
+
+override XEN_TARGET_ARCH = x86_32
+XEN_ROOT = ../../..
+CFLAGS := -I$(XEN_ROOT)/tools/libxc -I.
+include $(XEN_ROOT)/tools/Rules.mk
+
+# Disable PIE/SSP if GCC supports them. They can break us.
+CFLAGS += $(call cc-option,$(CC),-nopie,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+
+CFLAGS += -fno-builtin -O2 -msoft-float
+
+.PHONY: all
+all: extboot.bin
+
+%.o: %.S
+ $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+extboot.img: extboot.o
+ $(LD) $(LDFLAGS_DIRECT) --oformat binary -Ttext 0 -o $@ $<
+
+extboot.bin: extboot.img signrom
+ ./signrom extboot.img extboot.bin
+
+signrom: signrom.c
+ $(HOSTCC) $(HOSTCFLAGS) -o $@ $^
+
+clean:
+ $(RM) -f *.o *.img *.bin signrom *~
--- /dev/null
+Working
+-------
+
+Ubuntu Server 7.04 (i386)
+Windows 2000 Professional (i386)
+Windows XP SP2 (i386)
--- /dev/null
+/*
+ * Extended Boot Option ROM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ */
+
+.code16
+.text
+ .global _start
+_start:
+ .short 0xaa55
+ .byte (_end - _start) / 512
+
+ push %ax
+ push %bx
+ push %cx
+ push %dx
+ push %ds
+
+ /* setup ds so we can access the IVT */
+ xor %ax, %ax
+ mov %ax, %ds
+
+ /* save old int 19 at int 2b */
+ mov $(0x19 * 4), %bx
+ mov 0(%bx), %ax
+ mov 2(%bx), %cx
+
+ mov $(0x2b * 4), %bx
+ mov %ax, 0(%bx)
+ mov %cx, 2(%bx)
+
+ /* install our int 19 handler */
+ mov $(0x19 * 4), %bx
+ mov $int19_handler, %ax
+ mov %ax, 0(%bx)
+ mov %cs, 2(%bx)
+
+ pop %ds
+ pop %dx
+ pop %cx
+ pop %bx
+ pop %ax
+ lret
+
+int19_handler:
+ push %ax
+ push %bx
+ push %cx
+ push %dx
+ push %ds
+
+ movw $0x404, %dx
+ inb %dx, %al
+ cmp $1, %al
+ jne 1f
+
+ /* hook int13 */
+ /* setup ds to access IVT */
+ xor %ax, %ax
+ mov %ax, %ds
+
+ /* save old int 13 to int 2c */
+ mov $(0x13 * 4), %bx
+ mov 0(%bx), %ax
+ mov 2(%bx), %cx
+
+ mov $(0x2c * 4), %bx
+ mov %ax, 0(%bx)
+ mov %cx, 2(%bx)
+
+ /* install our int 13 handler */
+ mov $(0x13 * 4), %bx
+ mov $int13_handler, %ax
+
+ mov %ax, 0(%bx)
+ mov %cs, 2(%bx)
+
+1: pop %ds
+ pop %dx
+ pop %cx
+ pop %bx
+ pop %ax
+ int $0x2b
+
+#define FLAGS_CF 0x01
+
+.macro clc
+ push %ax
+ pushf
+ pop %ax
+ and $(~FLAGS_CF), %ax
+ push %ax
+ popf
+ pop %ax
+.endm
+
+.macro stc
+ push %ax
+ pushf
+ pop %ax
+ or $(FLAGS_CF), %ax
+ push %ax
+ popf
+ pop %ax
+.endm
+
+/* we clobber %bx */
+.macro alloca size
+ push %ds
+ push %bp
+ mov %sp, %bp /* remember the current stack position */
+
+ mov %ss, %bx
+ mov %bx, %ds
+
+ sub \size, %sp
+ and $(~0x0F), %sp
+ mov %sp, %bx
+
+ push %bp
+ mov 0(%bp), %bp
+.endm
+
+/* we clobber %bp */
+.macro allocbpa size
+ mov %sp, %bp /* remember the current stack position */
+ sub \size, %sp
+ and $(~0x0F), %sp
+ push %bp
+ mov %sp, %bp
+ add $2, %bp
+.endm
+
+.macro freea
+ pop %sp
+ add $2, %sp
+ pop %ds
+.endm
+
+.macro freebpa
+ pop %sp
+.endm
+
+.macro dump reg
+ push %ax
+ push %dx
+
+ mov \reg, %ax
+ mov $0x406, %dx
+ outw %ax, %dx
+
+ pop %dx
+ pop %ax
+.endm
+
+.macro callout value
+ push %bp
+ push %bx
+ mov %sp, %bp
+ alloca $16
+ push %ax
+ push %dx
+
+ mov %ax, 0(%bx) /* ax */
+ mov 0(%bp), %ax /* bx */
+ mov %ax, 2(%bx)
+ mov %cx, 4(%bx) /* cx */
+ mov %dx, 6(%bx) /* dx */
+ mov %si, 8(%bx) /* si */
+ mov %ds, 10(%bx) /* ds */
+ mov %es, 12(%bx) /* ds */
+ movw \value, 14(%bx) /* value */
+
+ mov %bx, %ax
+ shr $4, %ax
+ mov %ds, %dx
+ add %dx, %ax
+
+ mov $0x407, %dx
+ outw %ax, %dx
+
+ pop %dx
+ pop %ax
+ freea
+ pop %bx
+ pop %bp
+.endm
+
+send_command:
+ push %bp
+ mov %sp, %bp
+ push %ax
+ push %bx
+ push %dx
+
+ mov 4(%bp), %ax
+ shr $4, %ax
+ and $0x0FFF, %ax
+ mov %ss, %bx
+ add %bx, %ax
+
+ mov $0x405, %dx
+ outw %ax, %dx
+
+ pop %dx
+ pop %bx
+ pop %ax
+ pop %bp
+
+ push %ax
+ mov 2(%bx), %ax
+ pop %ax
+
+ ret
+
+add32: /* lo, hi, lo, hi */
+ push %bp
+ mov %sp, %bp
+
+ movw 4(%bp), %cx /* hi */
+ movw 6(%bp), %dx /* lo */
+
+ add 10(%bp), %dx
+ jnc 1f
+ add $1, %cx
+1: add 8(%bp), %cx
+
+ pop %bp
+ ret
+
+mul32: /* lo, hi, lo, hi */
+ /* 10(%bp), 8(%bp), 6(%bp), 4(%bp) */
+ push %bp
+ mov %sp, %bp
+ push %ax
+ push %bx
+
+ xor %cx, %cx
+ xor %dx, %dx
+
+ /* for (i = 0; i < 16;) */
+ xor %bx, %bx
+0:
+ cmp $16, %bx
+ jge 2f
+
+ mov 6(%bp), %ax
+ and $1, %ax
+ cmp $1, %ax
+ jne 1f
+ push 10(%bp)
+ push 8(%bp)
+ push %dx
+ push %cx
+ call add32
+ add $8, %sp
+1:
+ shlw $1, 8(%bp)
+ movw 10(%bp), %ax
+ and $0x8000, %ax
+ cmp $0x8000, %ax
+ jne 1f
+ orw $1, 8(%bp)
+1:
+ shlw $1, 10(%bp)
+ shrw $1, 6(%bp)
+
+ /* i++) { */
+ add $1, %bx
+ jmp 0b
+
+2:
+ pop %bx
+ pop %ax
+ pop %bp
+ ret
+
+disk_reset:
+ movb $0, %ah
+ clc
+ ret
+
+/* this really should be a function, not a macro but i'm lazy */
+.macro read_write_disk_sectors cmd
+ push %ax
+ push %bx
+ push %cx
+ push %dx
+ push %si
+
+ push %bp
+ sub $10, %sp
+ mov %sp, %bp
+
+ /* save nb_sectors */
+ mov %al, 6(%bp)
+ movb $0, 7(%bp)
+
+ /* save buffer */
+ mov %bx, 8(%bp)
+
+ /* cylinders */
+ xor %ax, %ax
+ mov %cl, %al
+ shl $2, %ax
+ and $0x300, %ax
+ mov %ch, %al
+ mov %ax, 0(%bp)
+
+ /* heads */
+ xor %ax, %ax
+ mov %dh, %al
+ mov %ax, 2(%bp)
+
+ /* sectors - 1 */
+ xor %ax, %ax
+ mov %cl, %al
+ and $0x3F, %al
+ sub $1, %ax
+ mov %ax, 4(%bp)
+
+ alloca $8
+
+ movw $0, 0(%bx) /* read c,h,s */
+ push %bx
+ call send_command
+ add $2, %sp
+
+ mov 6(%bx), %ax /* total_sectors */
+ mov 2(%bp), %si /* *= heads */
+ mul %si
+ add 4(%bp), %ax /* += sectors - 1 */
+
+ push 4(%bx) /* total_heads */
+ push $0
+ push 6(%bx) /* total_sectors */
+ push $0
+ call mul32
+ add $8, %sp
+
+ push 0(%bp) /* cylinders */
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ add %ax, %dx
+ jnc 1f
+ add $1, %cx
+1:
+ freea
+
+ alloca $16
+
+ movw \cmd, 0(%bx) /* read */
+ movw 6(%bp), %ax /* nb_sectors */
+ movw %ax, 2(%bx)
+ movw %es, 4(%bx) /* segment */
+ movw 8(%bp), %ax /* offset */
+ mov %ax, 6(%bx)
+ movw %dx, 8(%bx) /* sector */
+ movw %cx, 10(%bx)
+ movw $0, 12(%bx)
+ movw $0, 14(%bx)
+
+ push %bx
+ call send_command
+ add $2, %sp
+
+ freea
+
+ add $10, %sp
+ pop %bp
+
+ pop %si
+ pop %dx
+ pop %cx
+ pop %bx
+ pop %ax
+
+ mov $0, %ah
+ clc
+ ret
+.endm
+
+read_disk_sectors:
+ read_write_disk_sectors $0x01
+
+write_disk_sectors:
+ read_write_disk_sectors $0x02
+
+read_disk_drive_parameters:
+ push %bx
+
+ /* allocate memory for packet, pointer gets returned in bx */
+ alloca $8
+
+ /* issue command */
+ movw $0, 0(%bx) /* cmd = 0, read c,h,s */
+ push %bx
+ call send_command
+ add $2, %sp
+
+ /* normalize sector value */
+ movb 6(%bx), %cl
+ andb $0x3F, %cl
+ movb %cl, 6(%bx)
+
+ /* normalize cylinders */
+ subw $2, 2(%bx)
+
+ /* normalize heads */
+ subw $1, 4(%bx)
+
+ /* return code */
+ mov $0, %ah
+
+ /* cylinders */
+ movb 2(%bx), %ch
+ movb 3(%bx), %cl
+ shlb $6, %cl
+ andb $0xC0, %cl
+
+ /* sectors */
+ orb 6(%bx), %cl
+
+ /* heads */
+ movb 4(%bx), %dh
+
+ /* drives */
+ movb $1, %dl
+
+ /* status */
+ mov $0, %ah
+
+ freea
+
+ pop %bx
+
+ /* do this last since it's the most sensitive */
+ clc
+ ret
+
+alternate_disk_reset:
+ movb $0, %ah
+ clc
+ ret
+
+read_disk_drive_size:
+ push %bx
+ alloca $8
+
+ movw $0, 0(%bx) /* cmd = 0, read c,h,s */
+ push %bx
+ call send_command
+ add $2, %sp
+
+ /* cylinders - 1 to cx:dx */
+ mov 2(%bx), %dx
+ xor %cx, %cx
+ sub $1, %dx
+
+ /* heads */
+ push 4(%bx)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* sectors */
+ push 6(%bx)
+ push $0
+ push %dx
+ push %cx
+ call mul32
+ add $8, %sp
+
+ /* status */
+ mov $3, %ah
+
+ freea
+ pop %bx
+
+ clc
+ ret
+
+check_if_extensions_present:
+ mov $0x30, %ah
+ mov $0xAA55, %bx
+ mov $0x07, %cx
+ clc
+ ret
+
+.macro extended_read_write_sectors cmd
+ cmpb $10, 0(%si)
+ jg 1f
+ mov $1, %ah
+ stc
+ ret
+1:
+ push %ax
+ push %bp
+ allocbpa $16
+
+ movw \cmd, 0(%bp) /* read */
+ movw 2(%si), %ax /* nb_sectors */
+ movw %ax, 2(%bp)
+ movw 4(%si), %ax /* offset */
+ movw %ax, 6(%bp)
+ movw 6(%si), %ax /* segment */
+ movw %ax, 4(%bp)
+ movw 8(%si), %ax /* block */
+ movw %ax, 8(%bp)
+ movw 10(%si), %ax
+ movw %ax, 10(%bp)
+ movw 12(%si), %ax
+ movw %ax, 12(%bp)
+ movw 14(%si), %ax
+ movw %ax, 14(%bp)
+
+ push %bp
+ call send_command
+ add $2, %sp
+
+ freebpa
+ pop %bp
+ pop %ax
+
+ mov $0, %ah
+ clc
+ ret
+.endm
+
+extended_read_sectors:
+ extended_read_write_sectors $0x01
+
+extended_write_sectors:
+ extended_read_write_sectors $0x02
+
+get_extended_drive_parameters:
+ mov $1, %ah
+ stc
+ ret
+
+terminate_disk_emulation:
+ mov $1, %ah
+ stc
+ ret
+
+int13_handler:
+ cmp $0x80, %dl
+ je 1f
+ int $0x2c
+ iret
+1:
+ cmp $0x0, %ah
+ jne 1f
+ call disk_reset
+ iret
+1:
+ cmp $0x2, %ah
+ jne 1f
+ call read_disk_sectors
+ iret
+1:
+ cmp $0x8, %ah
+ jne 1f
+ call read_disk_drive_parameters
+ iret
+1:
+ cmp $0x15, %ah
+ jne 1f
+ call read_disk_drive_size
+ iret
+1:
+ cmp $0x41, %ah
+ jne 1f
+ call check_if_extensions_present
+ iret
+1:
+ cmp $0x42, %ah
+ jne 1f
+ call extended_read_sectors
+ iret
+1:
+ cmp $0x48, %ah
+ jne 1f
+ call get_extended_drive_parameters
+ iret
+1:
+ cmp $0x4b, %ah
+ jne 1f
+ call terminate_disk_emulation
+ iret
+1:
+ cmp $0x0d, %ah
+ jne 1f
+ call alternate_disk_reset
+ iret
+1:
+ cmp $0x03, %ah
+ jne 1f
+ call write_disk_sectors
+ iret
+1:
+ cmp $0x43, %ah
+ jne 1f
+ call extended_write_sectors
+ iret
+1:
+ int $0x18 /* boot failed */
+ iret
+
+.align 512, 0
+_end:
--- /dev/null
+/*
+ * Extended Boot Option ROM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ * Authors: Anthony Liguori <aliguori@us.ibm.com>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ FILE *fin, *fout;
+ char buffer[512], oldbuffer[512];
+ int i, size, lag = 0;
+ uint8_t sum = 0;
+
+ if (argc != 3) {
+ printf("Usage: %s ROM OUTPUT\n", argv[0]);
+ return 1;
+ }
+
+ fin = fopen(argv[1], "rb");
+ fout = fopen(argv[2], "wb");
+
+ if (fin == NULL || fout == NULL) {
+ fprintf(stderr, "Could not open input/output files\n");
+ return 1;
+ }
+
+ do {
+ size = fread(buffer, 512, 1, fin);
+ if (size == 1) {
+ for (i = 0; i < 512; i++)
+ sum += buffer[i];
+
+ if (lag) {
+ if (fwrite(oldbuffer, 512, 1, fout) != 1) {
+ fprintf(stderr, "Write failed\n");
+ return 1;
+ }
+ }
+ lag = 1;
+ memcpy(oldbuffer, buffer, 512);
+ }
+ } while (size == 1);
+
+ if (size != 0) {
+ fprintf(stderr, "Failed to read from input file\n");
+ return 1;
+ }
+
+ oldbuffer[511] = -sum;
+
+ if (fwrite(oldbuffer, 512, 1, fout) != 1) {
+ fprintf(stderr, "Failed to write to output file\n");
+ return 1;
+ }
+
+ fclose(fin);
+ fclose(fout);
+
+ return 0;
+}
sh ./mkhex vgabios_cirrusvga ../vgabios/VGABIOS-lgpl-latest.cirrus.bin >> roms.h
sh ./mkhex vmxassist ../vmxassist/vmxassist.bin >> roms.h
cat ../etherboot/eb-rtl8139.zrom.h >> roms.h
+ sh ./mkhex extboot ../extboot/extboot.bin >> roms.h
.PHONY: clean
clean:
#define VGABIOS_PHYSICAL_ADDRESS 0x000C0000
#define ETHERBOOT_PHYSICAL_ADDRESS 0x000C8000
#define VMXASSIST_PHYSICAL_ADDRESS 0x000D0000
+#define EXTBOOT_PHYSICAL_ADDRESS 0x000DF800
#define SMBIOS_PHYSICAL_ADDRESS 0x000E9000
#define SMBIOS_MAXIMUM_SIZE 0x00001000
#define ACPI_PHYSICAL_ADDRESS 0x000EA000
return ((boot_order & 0xf0) == 0x40);
}
+static int must_load_extboot(void)
+{
+ return (inb(0x404) == 1);
+}
+
/* Replace possibly erroneous memory-size CMOS fields with correct values. */
static void cmos_write_memory_size(void)
{
int main(void)
{
int acpi_sz = 0, vgabios_sz = 0, etherboot_sz = 0, rombios_sz, smbios_sz;
+ int extboot_sz = 0;
printf("HVM Loader\n");
etherboot_sz = sizeof(etherboot);
}
+ if ( must_load_extboot() )
+ {
+ printf("Loading EXTBOOT ...\n");
+ memcpy((void *)EXTBOOT_PHYSICAL_ADDRESS,
+ extboot, sizeof(extboot));
+ extboot_sz = sizeof(extboot);
+ }
+
if ( get_acpi_enabled() )
{
printf("Loading ACPI ...\n");
printf(" %05x-%05x: Etherboot ROM\n",
ETHERBOOT_PHYSICAL_ADDRESS,
ETHERBOOT_PHYSICAL_ADDRESS + etherboot_sz - 1);
+ if ( extboot_sz )
+ printf(" %05x-%05x: Extboot ROM\n",
+ EXTBOOT_PHYSICAL_ADDRESS,
+ EXTBOOT_PHYSICAL_ADDRESS + extboot_sz - 1);
if ( use_vmxassist() )
printf(" %05x-%05x: VMXAssist\n",
VMXASSIST_PHYSICAL_ADDRESS,
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
-VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) extboot.o
ifeq ($(ARCH),ia64)
VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
else
--- /dev/null
+/*
+ * Extended boot option ROM support.
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "vl.h"
+
+/* Extended Boot ROM suport */
+
+union extboot_cmd
+{
+ uint16_t type;
+ struct {
+ uint16_t type;
+ uint16_t cylinders;
+ uint16_t heads;
+ uint16_t sectors;
+ } query_geometry;
+ struct {
+ uint16_t type;
+ uint16_t nb_sectors;
+ uint16_t segment;
+ uint16_t offset;
+ uint64_t sector;
+ } xfer;
+};
+
+static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
+{
+ bdrv_get_geometry_hint(bs, c, h, s);
+
+ if (*c <= 1024) {
+ *c >>= 0;
+ *h <<= 0;
+ } else if (*c <= 2048) {
+ *c >>= 1;
+ *h <<= 1;
+ } else if (*c <= 4096) {
+ *c >>= 2;
+ *h <<= 2;
+ } else if (*c <= 8192) {
+ *c >>= 3;
+ *h <<= 3;
+ } else {
+ *c >>= 4;
+ *h <<= 4;
+ }
+
+ /* what is the correct algorithm for this?? */
+ if (*h == 256) {
+ *h = 255;
+ *c = *c + 1;
+ }
+}
+
+static uint32_t extboot_read(void *opaque, uint32_t addr)
+{
+ int *pcmd = opaque;
+ return *pcmd;
+}
+
+static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
+{
+ union extboot_cmd *cmd = (void *)(phys_ram_base + ((value & 0xFFFF) << 4));
+ BlockDriverState *bs = opaque;
+ int cylinders, heads, sectors, err;
+
+ get_translated_chs(bs, &cylinders, &heads, §ors);
+
+ if (cmd->type == 0x01 || cmd->type == 0x02) {
+ target_ulong pa = cmd->xfer.segment * 16 + cmd->xfer.segment;
+
+ /* possible buffer overflow */
+ if ((pa + cmd->xfer.nb_sectors * 512) > phys_ram_size)
+ return;
+ }
+
+ switch (cmd->type) {
+ case 0x00:
+ cmd->query_geometry.cylinders = cylinders;
+ cmd->query_geometry.heads = heads;
+ cmd->query_geometry.sectors = sectors;
+ cpu_physical_memory_set_dirty((value & 0xFFFF) << 4);
+ break;
+ case 0x01:
+ err = bdrv_read(bs, cmd->xfer.sector, phys_ram_base +
+ cmd->xfer.segment * 16 + cmd->xfer.offset,
+ cmd->xfer.nb_sectors);
+ if (err)
+ printf("Read failed\n");
+ break;
+ case 0x02:
+ err = bdrv_write(bs, cmd->xfer.sector, phys_ram_base +
+ cmd->xfer.segment * 16 + cmd->xfer.offset,
+ cmd->xfer.nb_sectors);
+ if (err)
+ printf("Write failed\n");
+
+ cpu_physical_memory_set_dirty(cmd->xfer.segment * 16 + cmd->xfer.offset);
+ break;
+ }
+}
+
+void extboot_init(BlockDriverState *bs, int cmd)
+{
+ int *pcmd;
+
+ pcmd = qemu_mallocz(sizeof(int));
+ if (!pcmd) {
+ fprintf(stderr, "Error allocating memory\n");
+ exit(1);
+ }
+
+ *pcmd = cmd;
+ register_ioport_read(0x404, 1, 1, extboot_read, pcmd);
+ register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
+}
int pmac_ide_init (BlockDriverState **hd_table,
SetIRQFunc *set_irq, void *irq_opaque, int irq);
+/* extboot.c */
+void extboot_init(BlockDriverState *bs, int cmd);
+
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);